#pragma once

#include "idpool.h"
#include <map>

#define DEFAULT_POOL_SIZE 65535

template < class CONCRETE_ACTOR, class REPLICA >
class Message;

template < class CONCRETE_ACTOR, class REPLICA >
class ActorsFactory
{
	friend class Id;
public:
	class Id
	: public IdPool < CONCRETE_ACTOR >::Id
	{
		friend class Message < CONCRETE_ACTOR, REPLICA >;
	public:
		typedef typename IdPool < CONCRETE_ACTOR >::Id IdFromPool;
		Id ()
		: factory ( 0 )
		{	
		}
		Id ( ActorsFactory < CONCRETE_ACTOR, REPLICA > * factory, const IdFromPool & id )
		: IdPool < CONCRETE_ACTOR >::Id ( id )
		, factory ( factory )
		{	
		}
		const REPLICA * GetReplica () const
		{
			CONCRETE_ACTOR * actor = GetActor ();
			if ( actor )
				return & actor->GetReplica ();
			else
				return 0;
		}
		void Delete () const
		{
			if ( factory )
				factory->Delete ( * this );
		}
	private:
		CONCRETE_ACTOR * GetActor () const
		{
			if ( factory )
				return factory->Get ( * this );
			else
				return 0;
		}
	private:
		ActorsFactory < CONCRETE_ACTOR, REPLICA > * factory;
	};
public:
	ActorsFactory ( int poolSize = DEFAULT_POOL_SIZE )
	: idPool ( poolSize )
	{
	}
	virtual ~ActorsFactory ()
	{
		for ( ActorsIt it = allActors.begin (); it != allActors.end (); it++ )
			delete it->second;
	}
	int InstancesCount () const
	{
		return int ( allActors.size () );
	}
	void HandleMessages ()
	{
		for ( ActorsIt it = allActors.begin (); it != allActors.end (); it++ )
			it->second->HandleMessages ();
	}
	void UpdateReplicas ()
	{
		for ( ActorsIt it = allActors.begin (); it != allActors.end (); it++ )
			it->second->DoUpdateReplica ();
	}
protected:
	Id RegisterNewActor ( CONCRETE_ACTOR * actor )
	{
		assert ( actor );
		Id id ( this, idPool.CreateNewId () );
		allActors [ id ] = actor;
		actor->SetId ( id );
		actor->DoUpdateReplica ();
		return id;
	}
private:
	CONCRETE_ACTOR * Get ( const Id & id )
	{
		ActorsIt it = allActors.find ( id );
		if ( it != allActors.end () )
			return it->second;
		return 0;
	}
	void Delete ( const Id & id )
	{
		idPool.DeleteId ( id );
		ActorsIt it = allActors.find ( id );
		if ( it != allActors.end () )
		{
			delete it->second;
			allActors.erase ( it );
		}
	}
private:
	typedef typename std::map < Id, CONCRETE_ACTOR * >::iterator ActorsIt;
	IdPool < CONCRETE_ACTOR > idPool;
	std::map < Id, CONCRETE_ACTOR * > allActors;
};
